<script setup lang="ts">
import type { PropType } from 'vue'
import { computed, nextTick, reactive, ref, toRaw, watch } from 'vue'
import type { TableInstance, TableRowSelection, TreeInstance } from '@arco-design/web-vue'
import { useI18n } from 'vue-i18n'
import { Search } from 'lucide-vue-next'
import { getMatrixRoles, getOrgTree, getRolePagerModel } from '@/api'
import { filterTreeData } from '@/utils/tools'
import ValidateTagInput from '@/components/common/ValidateTagInput.vue'

defineOptions({ name: 'RoleTagInput' })

const $props = defineProps({
  data: {
    type: Array as PropType<Record<string, unknown>[]>,
    default: () => [],
  },
  modalTitle: {
    type: String as PropType<string>,
    default: 'Role selection',
  },
  multiple: {
    type: Boolean as PropType<boolean>,
    default: true,
  },
  rowKey: {
    type: String as PropType<string>,
    default: 'sn',
  },
  required: {
    type: Boolean as PropType<boolean>,
    default: true,
  },
  validator: {
    type: Function as PropType<() => boolean>,
    default: undefined,
  },
})
const $emits = defineEmits(['update:data', 'change'])

const { t } = useI18n()

const modalVisible = ref(false)
const modalValues = ref<string[]>([])
const modalCheckedValues = ref<any[]>([])

const computedTags = computed<string[]>({
  get: () => {
    if (Array.isArray(toRaw($props.data))) {
      return $props.data.map(i => i.name as string)
    }
    return []
  },
  set: (names) => {
    const newValues = modalCheckedValues.value.filter(i => names.includes(i.name))
    $emits('update:data', newValues)
    $emits('change', newValues)
  },
})

watch(
  () => $props.data,
  () => {
    modalValues.value = ($props.data || []).map(i => i[$props.rowKey] as string)
    modalCheckedValues.value = [...($props.data || [])]
  },
  { immediate: true, deep: true },
)

const loading = ref(false)
const orgData = ref<any[]>([])
const orgTreeRef = ref<TreeInstance>()

const normalRoleData = ref<any[]>([])
const groupRoleData = ref<any[]>([])
const companyRoleData = ref<any[]>([])
const totalPerson = ref(0)
const orgFilterText = ref('')
const pagination = ref({ pageSize: 15, pageNum: 1 })
const entity = ref({ companyId: '', keyword: '' })
const rowSelection = reactive<TableRowSelection>({
  type: $props.multiple ? 'checkbox' : 'radio',
  showCheckedAll: false,
  onlyCurrent: false,
})

const activeTab = ref('normal')

const normalRoleTableRef = ref<TableInstance>()
const companyRoleTableRef = ref<TableInstance>()
const groupRoleTableRef = ref<TableInstance>()

const columns = computed(() => [
  { title: t('Name'), dataIndex: 'name' },
  { title: t('Code'), dataIndex: 'sn' },
  { title: t('Company name'), dataIndex: 'companyName' },
])

const computedOrgData = computed(() => {
  return filterTreeData(orgData.value, 'name', orgFilterText.value)
})

function commonAttrFilter(r: any) {
  return {
    name: r.name,
    sn: r.sn,
    id: r.id,
    type: r.type,
    companyName: r.companyName,
  }
}

async function getOrgTreeData() {
  try {
    orgData.value = await getOrgTree()
    await nextTick()
    orgTreeRef.value?.expandAll(true)
  }
  catch (e) {
    console.error(e)
    orgData.value = []
  }
}
async function getNormalRolePageData(pageNum?: number) {
  try {
    loading.value = true
    if (pageNum) {
      pagination.value.pageNum = pageNum
    }
    const {
      data: { rows, total },
    } = await getRolePagerModel({
      pager: pagination.value,
      entity: entity.value,
    })
    normalRoleData.value = (rows || []).map(commonAttrFilter)
    totalPerson.value = total
  }
  catch (e) {
    console.error(e)
    normalRoleData.value = []
    totalPerson.value = 0
  }
  finally {
    loading.value = false
  }
}
async function getMatrixGroupRolesData() {
  try {
    const { data: groupData } = await getMatrixRoles({ roleType: 1 })
    groupRoleData.value = (groupData || []).map(commonAttrFilter)
  }
  catch (e) {
    console.error(e)
    normalRoleData.value = []
  }
}
async function getMatrixCompanyRolesData() {
  try {
    const { data: companyData } = await getMatrixRoles({ roleType: 2 })
    companyRoleData.value = (companyData || []).map(commonAttrFilter)
  }
  catch (e) {
    console.error(e)
    normalRoleData.value = []
  }
}
const findIdx = (person: any, key: string) => person[$props.rowKey] === key
function updateSelectOrg(_, data) {
  const { node } = data
  entity.value.companyId = node.companyId
  getNormalRolePageData(1)
}
function toggleNormalRowSelect(row) {
  const key = row[$props.rowKey]
  const selected = modalCheckedValues.value.findIndex(i => findIdx(i, key)) > -1
  normalRoleTableRef.value?.select(row[$props.rowKey], !selected)
  // 需要手动触发选中数据更新
  changeNormalSelect(row, key)
}
function changeNormalSelect(_, key) {
  changeSelect(normalRoleData.value, key)
}
function toggleCompanyRoleSelect(row) {
  const key = row[$props.rowKey]
  const selected = modalCheckedValues.value.findIndex(i => findIdx(i, key)) > -1
  companyRoleTableRef.value?.select(row[$props.rowKey], !selected)
  changeCompanySelect(row, key)
}
function changeCompanySelect(_, key) {
  changeSelect(companyRoleData.value, key)
}
function toggleGroupRoleSelect(row) {
  const key = row[$props.rowKey]
  const selected = modalCheckedValues.value.findIndex(i => findIdx(i, key)) > -1
  groupRoleTableRef.value?.select(row[$props.rowKey], !selected)
  changeGroupSelect(row, key)
}
function changeGroupSelect(_, key) {
  changeSelect(groupRoleData.value, key)
}
function changeSelect(roleData, key) {
  if ($props.multiple) {
    const idx = modalCheckedValues.value.findIndex(i => findIdx(i, key))
    if (idx > -1) {
      modalCheckedValues.value.splice(idx, 1)
    }
    else {
      modalCheckedValues.value.push(roleData.find(i => findIdx(i, key)))
    }
  }
  else {
    modalCheckedValues.value = [roleData.find(i => findIdx(i, key))]
  }
}

function removeCheckedValue(item: any, idx: number) {
  modalValues.value = modalValues.value.filter(i => i !== item[$props.rowKey])
  modalCheckedValues.value.splice(idx, 1)
}

function updateModalValues() {
  $emits('update:data', [...modalCheckedValues.value])
  $emits('change', [...modalCheckedValues.value])
}

async function openModal() {
  try {
    loading.value = true
    modalVisible.value = true
    await Promise.all([
      getOrgTreeData(),
      getNormalRolePageData(),
      getMatrixGroupRolesData(),
      getMatrixCompanyRolesData(),
    ])
  }
  finally {
    loading.value = false
  }
}
</script>

<template>
  <a-input-group>
    <ValidateTagInput
      v-if="!$slots.default && required"
      v-model="computedTags"
      :max-tag-count="3"
      :validator="validator"
      :placeholder="$t('Please select roles')"
    />
    <a-input-tag
      v-if="!$slots.default && !required"
      v-model="computedTags"
      :max-tag-count="3"
      :disabled-input="true"
      :placeholder="$t('Please select roles')"
    />
    <slot />
    <a-button type="primary" @click="openModal">
      <Search :size="14" />
    </a-button>
  </a-input-group>

  <a-drawer
    v-model:visible="modalVisible"
    width="80vw"
    :title="$t(modalTitle)"
    @ok="updateModalValues"
  >
    <a-spin
      :loading="loading"
      style="width: 100%; height: calc(100vh - 142px); overflow: hidden; box-sizing: border-box"
    >
      <div class="tag-input-flex">
        <div class="header-tags">
          <a-tag
            v-for="(i, idx) in modalCheckedValues"
            :key="i[rowKey]"
            color="arcoblue"
            closable
            @close="removeCheckedValue(i, idx)"
          >
            {{ i.name }}
          </a-tag>
        </div>
        <a-tabs v-model:active-key="activeTab">
          <a-tab-pane key="normal" :title="$t('Normal Roles')">
            <div class="tag-input-special-grid">
              <div class="left-org-tree">
                <a-input-group>
                  <a-input
                    v-model="orgFilterText"
                    :placeholder="$t('Please enter a name')"
                    allow-clear
                  />
                  <a-button type="primary">
                    <Search :size="14" />
                  </a-button>
                </a-input-group>
                <div class="tree-content">
                  <a-tree
                    ref="orgTreeRef"
                    :data="computedOrgData"
                    :field-names="{ title: 'name', key: 'id' }"
                    size="mini"
                    block-node
                    default-expand-all
                    @select="updateSelectOrg"
                  />
                </div>
              </div>
              <div class="right-table">
                <a-input-group>
                  <a-input
                    v-model="entity.keyword"
                    :placeholder="$t('Please enter a keyword or name')"
                    allow-clear
                  />
                  <a-button type="primary" @click="getNormalRolePageData(1)">
                    <Search :size="14" />
                  </a-button>
                </a-input-group>
                <div class="table-content">
                  <a-table
                    ref="normalRoleTableRef"
                    v-model:selected-keys="modalValues"
                    :row-key="rowKey"
                    :row-selection="rowSelection"
                    :scroll="{ y: '100%' }"
                    :columns="columns"
                    :data="normalRoleData"
                    :pagination="{
                      current: pagination.pageNum,
                      pageSize: pagination.pageSize,
                      total: totalPerson,
                      pageSizeOptions: [15, 30, 50, 100],
                      showTotal: true,
                      showPageSize: true,
                    }"
                    @row-click="toggleNormalRowSelect"
                    @select="changeNormalSelect"
                    @page-change="getNormalRolePageData"
                    @page-size-change="(val) =>
                      (pagination.pageSize = val) && getNormalRolePageData(1)"
                  />
                </div>
              </div>
            </div>
          </a-tab-pane>
          <a-tab-pane key="company" :title="$t('Matrix Company Roles')">
            <a-table
              ref="companyRoleTableRef"
              v-model:selected-keys="modalValues"
              :row-key="rowKey"
              :scroll="{ y: '100%' }"
              :row-selection="rowSelection"
              :columns="columns"
              :data="companyRoleData"
              :pagination="false"
              @row-click="toggleCompanyRoleSelect"
              @select="changeCompanySelect"
            />
          </a-tab-pane>
          <a-tab-pane key="group" :title="$t('Matrix Group Roles')">
            <a-table
              ref="groupRoleTableRef"
              v-model:selected-keys="modalValues"
              :row-key="rowKey"
              :scroll="{ y: '100%' }"
              :row-selection="rowSelection"
              :columns="columns"
              :data="groupRoleData"
              :pagination="false"
              @row-click="toggleGroupRoleSelect"
              @select="changeGroupSelect"
            />
          </a-tab-pane>
        </a-tabs>
      </div>
    </a-spin>
  </a-drawer>
</template>
